package com.langshixiaobai.shortlink.project.serivce.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.StrBuilder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.protobuf.ServiceException;
import com.langshixiaobai.shortlink.project.dao.entity.ShortLinkDO;
import com.langshixiaobai.shortlink.project.dao.mapper.ShortLinkMapper;
import com.langshixiaobai.shortlink.project.dto.req.ShortLinkCreateReqDTO;
import com.langshixiaobai.shortlink.project.dto.req.ShortLinkPageReqDTO;
import com.langshixiaobai.shortlink.project.dto.req.ShortLinkUpdateReqDTO;
import com.langshixiaobai.shortlink.project.dto.resp.ShortLinkCreateRespDTO;
import com.langshixiaobai.shortlink.project.dto.resp.ShortLinkGroupCountQueryRespDTO;
import com.langshixiaobai.shortlink.project.dto.resp.ShortLinkPageRespDTO;
import com.langshixiaobai.shortlink.project.serivce.ShortLinkService;
import com.langshixiaobai.shortlink.project.tookit.HashUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;


@Service
@RequiredArgsConstructor
@Slf4j
public class ShortLinkServiceImp extends ServiceImpl<ShortLinkMapper, ShortLinkDO> implements ShortLinkService {

    @Autowired
    private final RBloomFilter rBloomFilter;

    @Override
    public ShortLinkCreateRespDTO createShortLink(ShortLinkCreateReqDTO requestParam) throws ServiceException {
        String shortLinkSuffix  =  generateSuffix(requestParam);
        String fullShortUrl = StrBuilder.create(requestParam.getDomain())
                .append("/")
                .append(shortLinkSuffix)
                .toString();
        ShortLinkDO shortLinkDO = ShortLinkDO.builder()
                .fullShortUrl(fullShortUrl)
                .shortUri(shortLinkSuffix)
                .originUrl(requestParam.getOriginUrl())
                .gid(requestParam.getGid())
                .describe(requestParam.getDescribe())
                .createdType(requestParam.getCreatedType())
                .domain(requestParam.getDomain())
                .validDate(requestParam.getValidDate())
                .validDateType(requestParam.getValidDateType())
                .enableStatus(0)
                .build();
        try {
            baseMapper.insert(shortLinkDO);
        }catch (DuplicateKeyException ex){
            // idx_unique_full-short-url
            LambdaQueryWrapper<ShortLinkDO> queryWrapper = Wrappers.lambdaQuery(ShortLinkDO.class)
                    .eq(ShortLinkDO::getFullShortUrl, fullShortUrl);
            ShortLinkDO hasShortLinkDO = baseMapper.selectOne(queryWrapper);
            if (hasShortLinkDO != null) {
                log.warn("短链接：{} 重复入库", fullShortUrl);
                throw new ServiceException("短链接生成重复");
            }
        }
        rBloomFilter.add(shortLinkSuffix);
        return ShortLinkCreateRespDTO.builder()
                .fullShortUrl(fullShortUrl)
                .originUrl(requestParam.getOriginUrl())
                .gid(requestParam.getGid())
                .build();
    }

    @Override
    public IPage<ShortLinkPageRespDTO> pageShortLink(ShortLinkPageReqDTO requestParam) {
        LambdaQueryWrapper<ShortLinkDO> queryWrapper = Wrappers.lambdaQuery(ShortLinkDO.class)
                .eq(ShortLinkDO::getGid, requestParam.getGid())
                .eq(ShortLinkDO::getEnableStatus, 0)
                .eq(ShortLinkDO::getDelFlag, 0);
        Page<ShortLinkDO> shortLinkDOPage = baseMapper.selectPage(new Page<ShortLinkDO>(), queryWrapper);

        return shortLinkDOPage.convert(each -> BeanUtil.copyProperties(each, ShortLinkPageRespDTO.class));
    }


    @Override
    public List<ShortLinkGroupCountQueryRespDTO> listGroupShortLinkCount(List<String> requestParam) {
        QueryWrapper<ShortLinkDO> queryWrapper = Wrappers.query(new ShortLinkDO())
                .select("gid as gid, count(*) as shortLinkCount")
                .in("gid", requestParam)
                .eq("enable_status", 0)
                .groupBy("gid");

        List<Map<String, Object>> maps = baseMapper.selectMaps(queryWrapper);
        return BeanUtil.copyToList(maps, ShortLinkGroupCountQueryRespDTO.class);

    }

    // 生成短连接
    private String generateSuffix(ShortLinkCreateReqDTO requestParam) throws ServiceException {
        int count  = 0;
        String shortLinkSuffix ;
        while(true){
            if(count > 10){
                throw new ServiceException("短连接频繁生成，稍后重试");
            }
            String originUrl = requestParam.getOriginUrl();
            originUrl += System.currentTimeMillis();
            shortLinkSuffix = HashUtil.hashToBase62(originUrl);
            if(!rBloomFilter.contains(shortLinkSuffix)){
                break;
            }
            count ++;
        }

        return shortLinkSuffix;
    }

    // 由于是分库分表，分片键如果改变，无法在查到
    // 所以查询时，先删除分片键，在进行更改
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateShortLink(ShortLinkUpdateReqDTO requestParam) {

    }
}
